package chatGUI;

import java.awt.Color;
import java.io.File;
import java.net.UnknownHostException;
import java.util.ArrayList;

import javax.swing.JFileChooser;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;

import people.User;
import people.UserType;
import chatController.ChatController;

/**
 * <b>Project ChatSystemG2 - INSA 4INFOA1 - 2013/2014</b>
 * <P>
 * <i>Package  chatGUI</i> <br>
 * ChatGUI is a view in the MVC design pattern. It is an observer, observing the model.
 * <br>
 * The GUI is the part of the chat system that the client sees.
 * <br>
 * It implements 2 interfaces: FromUser and ToUser, that are the relation between the GUI and the client.
 * <br>
 * It contains the following attributes: the windowconnection, the window opened to communicate and the controller.
 *
 * @author Sergio Gonzalez - Marie-Charlotte Bideaud
 */

public class ChatGUI implements FromUser, ToUser, GUIToCont {

	private WindowConnexion windowconnect;
	private WindowComunication windowcomunica;
	private ChatController controller;

	/**
	 * Constructor for the class ChatGUI
	 * 
	 * @param cont : ChatController 
	 * @throws UnknownHostException 
	 */
	public ChatGUI (ChatController cont) throws UnknownHostException {
		this.controller = cont;
		this.windowconnect = new WindowConnexion (this);
		this.windowcomunica = new WindowComunication (this);
	}

	// *****     INTERFACE FROMUSER     *****

	/**
	 * When the local user presses the "connect" button
	 * 
	 * @param username : String 
	 */
	public void clickConnectButton(String username) {
		controller.performConnect (username);
		this.windowcomunica.getLblTitle().setText("Welcome " + username + ". ");
	}

	/**
	 * When the local user presses the "disconnect" button or closes the chat window
	 */
	public void clickDisconnectButton() {
		controller.performDisconnect();
	}

	/**
	 * When the local user presses the "start chat" button after selected user in the userslist
	 * 
	 * @param firstUser : User
	 * @param tabList : ArrayList<ChatTab>
	 * @param tabbedPane : JTabbedPane 
	 * 
	 * @return ArrayList<ChatTab>
	 */
	public ArrayList<ChatTab> clickStartChatButton(User firstUser, ArrayList<ChatTab> tabList, JTabbedPane tabbedPane)  {
		boolean alreadyExists = false;
		for (int i = 0; i < tabList.size(); i++) {
			if (tabList.get(i).getUser().getIPAddr().equals(firstUser.getIPAddr())) {
				alreadyExists = true;
				break;
			}
		}
		if (!alreadyExists) { // if the tab corresponding to the user doesn't exist
			tabList = setChatWindow(firstUser, tabbedPane, tabList);
		} else  // if the tab already exists
			JOptionPane.showMessageDialog(null, "User already selected");
		return tabList;
	}

	/**
	 * When the local user presses the "send file" button
	 * 
	 * @param user : User
	 * @param file : File 
	 */
	public void clickSendFile(File file, User user) {
		user.setFilename(file.getAbsolutePath());
		user.setFilesize(file.length());
		User testUser = new User(controller.getLocaluser().getUsername(), UserType.FILEREQUEST);
		testUser.setIPAddr(user.getIPAddr());
		testUser.setFilename(file.getAbsolutePath());
		testUser.setFilesize(file.length());
		testUser.setText(user.getText());
		controller.performFileRequest(testUser);
	}

	/**
	 * Method to check if a correct username has been typed (if the field is not empty)
	 * 
	 * @param username : String 
	 */
	public void setUsername(String username) {
		if (username.equals("")) {
			JOptionPane.showMessageDialog(null, "Please, write your username");
		} else {
			// the user connects to the chat
			clickConnectButton(username);
		}
	}

	/**
	 * When the local user selects a user in the userslist
	 * 
	 * @param list : Jlist
	 * 
	 * @return boolean
	 */
	public boolean selectUsers(JList list) {
		int[] arrayUsers = list.getSelectedIndices();
		if (arrayUsers.length > 1)  // There are too many selected users 
			JOptionPane.showMessageDialog(null, "Select only 1 user");
		else {
			if (arrayUsers.length == 1) { // Only one user is selected : the chat can start
				return true;
			} else  // If there is no user selected
				JOptionPane.showMessageDialog(null, "Please, select a user");
		}
		return false;
	}

	/**
	 * When the local user selects a user or a group of users, a new tab is created and displayed
	 * 
	 * @param firstUser : User
	 * @param tabbedPane : JTabbedPane 
	 * @param tabList : ArrayList<ChatTab>
	 * 
	 * @return ArrayList<ChatTab>
	 */
	public ArrayList<ChatTab> setChatWindow(User firstUser, JTabbedPane tabbedPane, ArrayList<ChatTab> tabList) {
		ChatTab panel = new ChatTab(firstUser.getUsername(), firstUser, this);
		tabbedPane.addTab(firstUser.getUsername(), panel);
		tabList.add(panel);
		panel.focusText();
		return tabList;
	}

	/**
	 * When a message is sent or received, it is displayed in the corresponding chat tab
	 * 
	 * @param user : User
	 * @param textArea : JTextArea 
	 */
	public void setMessage(User user, JTextArea textArea) {
		textArea.append(user.getUsername() + ": " + user.getText() + "\n");
	}

	/**
	 * When the local presses the "send text" button or presses "Enter"  
	 * 
	 * @param text : String
	 * @param user : User
	 * @param textArea : JTextArea
	 */
	public void clickSendMessageButton(String text, User user, JTextArea textArea) {
		User testUser = new User(controller.getLocaluser().getUsername(), UserType.TEXT);
		testUser.setIPAddr(user.getIPAddr());
		testUser.setText(text);
		setMessage(testUser, textArea);
		controller.performSendText(testUser);
	}

	/**
	 * When the local user answers a file request 
	 * 
	 * @param user : User
	 * @param answer : boolean
	 */
	public void answerFile(User user, boolean answer) {
		User testUser = new User(controller.getLocaluser().getUsername(), UserType.FILEANSWER);
		testUser.setIPAddr(user.getIPAddr());
		testUser.setFilesize(user.getFilesize());
		testUser.setText(user.getText());
		testUser.setFilename(user.getFilename());
		testUser.setAnswer(answer);
		if (answer) {
			JFileChooser chooser = new JFileChooser(); 
			chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
			chooser.setDialogTitle("Select Directory");
			chooser.setAcceptAllFileFilterUsed(false);
			if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) { 
				testUser.setPath(""+chooser.getSelectedFile());
				testUser.setAnswer(true);
			} else {
				testUser.setPath("");
				testUser.setAnswer(false);
			}
		}
		controller.performAnswer(testUser);
	}

	// *****     INTERFACE GUIToCont     *****

	/**
	 * Method called when a text message is received : it has to be transfered to the local user
	 * @param user : User
	 * @param tabList : ArrayList<ChatTab>
	 * @return boolean
	 */
	@Override
	public boolean performMsgReceived(User user, ArrayList<ChatTab> tabList) {
		// TODO Auto-generated method stub
		boolean valid = false;
		for( ChatTab u : tabList ){
			if ( ( u.getUser().getUsername().equals(user.getUsername()) ) 
					&& ( u.getUser().getIPAddr().equals(user.getIPAddr()) ) ) {
				setMessage(user, u.getTextArea());
				u.focusText();
				valid = true;
			}
		}
		return newMessageReceived(valid);
	}

	/**
	 * Method called when a bye message is received : the user concerned is deleted from the userslist
	 * @param user : User
	 * @param tabList : ArrayList<ChatTab>
	 * @param tabbedPane : JTabbedPane
	 */
	@Override
	public void performDeleteUser(User user, ArrayList<ChatTab> tabList, JTabbedPane tabbedPane) {
		// TODO Auto-generated method stub
		deleteUserAlarm(user, tabList, tabbedPane);
	}

	/**
	 * Method called when a file request sent by the local user is refused 
	 * @param user : User
	 * @param tabList : ArrayList<ChatTab>
	 * @return boolean
	 */
	@Override
	public boolean performRefused(User user, ArrayList<ChatTab> tabList) {
		// TODO Auto-generated method stub
		return fileRefused(user, tabList);
	}

	/**
	 * Method called when a file request sent by the local user is accepted
	 * @param user : User
	 * @param tabList : ArrayList<ChatTab>
	 * @return boolean
	 */
	@Override
	public boolean performAccepted(User user, ArrayList<ChatTab> tabList) {
		// TODO Auto-generated method stub
		return fileAccepted(user, tabList);
	}
	
	/**
	 * Method called when a hello message is received : the new user has to be added to the userslist
	 * @param userlist : ArrayList<User>
	 * @param list : JList 
	 */
	@Override
	public void performNewUser(ArrayList<User> userlist, JList list) {
		// TODO Auto-generated method stub
		ArrayList<String> usernames = new ArrayList<String>();
		for (int i = 0; i<userlist.size(); i++) {
			usernames.add(userlist.get(i).getUsername()+" - "+userlist.get(i).getIPAddr());
		}
		newUserAlarm(usernames.toArray(), list);
	}

	/**
	 * Method called when a file request is received by the local user
	 */
	@Override
	public void performFileReceived() {
		// TODO Auto-generated method stub
		newFileReceived();
	}

	/**
	 * Method called when the remote user answers the local user 's file request 
	 * @param user : User
	 */
	@Override
	public void performAnswerRequest(User user) {
		// TODO Auto-generated method stub
		newFileRequest(user);
	}

	// *****     INTERFACE TOUSER     ***** 

	/**
	 * When a new user gets connected : updates the userslist
	 * 
	 * @param usernames : Object[]
	 * @param list : JList 
	 */
	public void newUserAlarm (Object[] usernames, JList list) {
		list.setListData(usernames);
	}

	/**
	 * Displays the windowconnect (and closes the the chat window if it is opened)   
	 */
	public void loginRequest() {
		windowcomunica.close();
		windowconnect.display();
	}

	/**
	 * Displays the windowcomunica 
	 */
	public void listOptionRequest() {
		this.windowconnect.close();
		this.windowcomunica.display();
	}

	/**
	 * When the local user receives a new text message, it is written in the corresponding tab 
	 * 
	 * @param valid : boolean
	 * 
	 * @return boolean
	 */
	public boolean newMessageReceived(boolean valid) {
		return valid;
	}

	/**
	 * When the remote user accepts the file request sent by the local user
	 * @param user : User
	 * @param tabList : ArrayList<ChatTab>
	 * @return boolean
	 */
	public boolean fileAccepted(User user, ArrayList<ChatTab> tabList) {
		boolean valid = false;
		for( ChatTab u : tabList ){
			if ( ( u.getUser().getUsername().equals(user.getUsername()) ) 
					&& ( u.getUser().getIPAddr().equals(user.getIPAddr()) ) ) {
				u.getTextArea().append("--> INFORMATION: File Accepted\n");
				u.focusText();
				valid = true;
			}
		}
		return newMessageReceived(valid);
	}

	/**
	 * When the remote user refuses the file request sent by the local user 
	 * @param user : User
	 * @param tabList : ArrayList<ChatTab>
	 * @return boolean
	 */
	public boolean fileRefused(User user, ArrayList<ChatTab> tabList) {
		boolean valid = false;
		for( ChatTab u : tabList ){
			if ( ( u.getUser().getUsername().equals(user.getUsername()) ) 
					&& ( u.getUser().getIPAddr().equals(user.getIPAddr()) ) ) {
				u.getTextArea().append("--> INFORMATION: File Refused\n");
				u.focusText();
				valid = true;
			}
		}
		return newMessageReceived(valid);
	}

	/**
	 * When the local user receives a file  
	 */
	public void newFileReceived() {

	}

	/**
	 * When a user gets disconnected, remove it from the userslist and remove the corresponding tab
	 * 
	 * @param user : User
	 * @param tabList : ArrayList<ChatTab>
	 * @param tabbedPane : JTabbedPane
	 */
	public void deleteUserAlarm(User user, ArrayList<ChatTab> tabList, JTabbedPane tabbedPane) {
		for (ChatTab ct : tabList) {
			if (ct.getUser().getIPAddr().equals(user.getIPAddr())) {
				tabList.remove(ct);
				tabbedPane.remove(ct);
				break;
			}
		}
	}

	/**
	 * When the local user receives a file request, and answers it
	 * 
	 * @param user : User
	 */
	public void newFileRequest(User user) {
		int option = JOptionPane.showConfirmDialog(null, "Do you want to save this file? \n"+user.getFilename(), "New File", JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE);
		if(option == JOptionPane.OK_OPTION)
		{
			answerFile(user, true);
		} else {
			answerFile(user, false);
		}
	}

	/**
	 * Getter for windowconnect
	 * 
	 * @return windowconnect
	 */
	public WindowConnexion getWindowconnect() {
		return windowconnect;
	}

	/**
	 * Setter for windowconnect
	 * 
	 * @param windowconnect : WindowConnexion
	 */
	public void setWindowconnect(WindowConnexion windowconnect) {
		this.windowconnect = windowconnect;
	}

	/**
	 * Getter for windowcomunica
	 * 
	 * @return windowcomunica
	 */
	public WindowComunication getWindowcomunica() {
		return windowcomunica;
	}

	/**
	 * Setter for windowcomunica
	 * 
	 * @param windowcomunica : WindowComunication
	 */
	public void setWindowcomunica(WindowComunication windowcomunica) {
		this.windowcomunica = windowcomunica;
	}
}
